// scalaxx - Scala XML eXtensions
// (c) 2009-2010, Normen Müller, normen.mueller@gmail.com
// $Id: Differ.scala 81 2010-05-13 12:38:41Z normen.mueller $
//package scalaxx.draft.diff
//import java.io.File
//import scala.xml.{NodeSeq, NodeBuffer, Node, Text, MetaData, Null}
//import scala.xml.XML.{loadFile}
//import scala.xml.Utility.{trimProper}
//import scaup.Views._
//import scaup.eq.Slit
//import scalaxx.Views._
//import scalaxx.path._
//import scalaxx.path.LocationPath
///** Companion to <code>Differ</code> class.
// * 
// * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
// * @version 0.0.4 */
//object Differ {
//  type E[M <: {def get(key: String): Option[Seq[T]]}, T] = scaup.eq.EquivalenceSystem[M, T]  
//  def diff(src: File, tgt: File): List[Command] = diff(new BaseEquivalenceSystem, src, tgt)  
//  def diff(src: NodeSeq, tgt: NodeSeq): List[Command] = diff(new BaseEquivalenceSystem, src, tgt)  
//  def diff(eqspec: File, src: File, tgt: File): List[Command] = diff(EquivalenceSystem.parse(eqspec), src, tgt)  
//  def diff(eqspec: File, src: NodeSeq, tgt: NodeSeq): List[Command] = diff(EquivalenceSystem.parse(eqspec), src, tgt)  
//  def diff[M <: MetaData, T >: Node](eqsys: E[M, T], src: File, tgt: File): List[Command] = 
//    try {
//      diff(eqsys, loadFile(src), loadFile(tgt))
//    } catch {
//      case e: org.xml.sax.SAXParseException => error(e.getMessage) //@todo better handling of ``empty'' XML files 
//    }  
//  def diff[M <: MetaData, T >: Node](eqsys: E[M, T], src: NodeSeq, tgt: NodeSeq) = new Differ(eqsys).diff(new NodeBuffer &+ (src map trimProper), new NodeBuffer &+ (tgt map trimProper))
//}
///** sdiff: Semantics-Based XML Differencing Algorithm.
// * 
// * For further information please refer to: 
// * 
// * Normen Müller, Change Management on Semi-Structured Documents, PhD thesis
// * School of Engineering & Science, Jacobs University Bremen, Campus Ring 1, 28759 Bremen, Germany
// * 
// * @thanks Serge Autexier and Marc Wagner for their initial discussions on the general differencing algorithm.
// * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
// * @version 0.0.4 */
//private [diff] class Differ[M <: MetaData, T >: Node](eqsys: scaup.eq.EquivalenceSystem[M, T]) {
//  import eqsys._
//  import scala.xml.NodeSeq._
//  /**@todo document */
//  def diff(src: NodeSeq, tgt: NodeSeq): List[Command] = diff(src, tgt, Root.childAt(1),Nil).reverse
//  /**@todo document */
//  private def diff(src: NodeSeq, tgt: NodeSeq, path: LocationPath, cs: List[Command]): List[Command] = (src,tgt) match {
//    case (Empty, Empty)                                   => cs        
//    case (Seq(hs@Text(_), ts@_*), Empty)                  => diff(ts, Empty, path++, remove(path.parent.text, elem(hs)) :: cs)
//    case (Seq(hs@Text(l), ts@_*), Seq(ht@Text(r), tt@_*)) => if(l != r) diff(ts, tt, path++, update(path.parent.text, elem(ht)) :: cs) else cs    
////  @draft: diff(ts, tt, path++, patch(path.parent.text, delta(scaup.util.Differ.diff(hs.text, ht.text))) :: cs)
//    case (Empty, Seq(ht, tt@_*))                          => diff(Empty, tt, path, append(path.parent, elem(ht)) :: cs)      
//    case (Seq(hs, ts@_*), Empty)                          => diff(ts, Empty, path++, remove(path, elem(hs)) :: cs)  	      
//    case (Seq(hs, ts@_*), _)                              => ((slit: Slit[Node]) =>
//      diff(ts, slit.after, path++, slit.focus match {
//        case Some(f) => diff(hs.child, f.child, path childAt 1, diff(hs, hs.attributes, f.attributes, path) ::: (slit.before match {
//          case Some(es) => List(before(path, (es map elem):_*))
//          case _        => Nil
//        }) ::: cs)            
//        case _ => (slit.before match {
//          case Some(es) => List(before(path, (es map elem):_*))
//          case _        => Nil
//        }) ::: List(remove(path, elem(hs))) ::: cs
//      })
//    )(findEquivTo(hs, tgt))
//      
//    //@alternative for previous case
//    //@todo test!
////    case (Seq(hs, ts@_*), _) =>
////      val insert = (x: Option[Seq[Node]]) => x match {
////        case Some(es) => before(path, (es map elem):_*) :: Nil
////        case None     => Nil
////      }
////      ((slit: Slit[Node]) =>
////        diff(ts, slit.after, if(ts isEmpty) path-- else path++, slit.focus match {
////          case Some(f) => diff(hs.child, f.child, if(hs.child isEmpty) path else path.childAt(1),
////                               diff(hs, hs.attributes, f.attributes, path) ::: insert(slit.before) ::: cs)            
////          case _       => insert(slit.before) ::: List(remove(path, elem(hs))) ::: cs
////        })
////      )(findEquivTo(hs, tgt))
//  }
//  /**@todo document */
//  private def diff(owner: Node, src: MetaData, tgt: MetaData, path: LocationPath) =
//    ((for(a: MetaData <- tgt) yield
//       src.elements find (_.key == a.key) match {
//         case Some(k) if (k.value != a.value) => Some(update(path.attribute(a.qname(owner)), elem(Text(a.value.text))))
//         case None                            => Some(append(path.attributes, attr(a.copy(Null))))
//         case _                               => None
//    }).toList filter (None !=) map (_.get)) ::: 
//     (for(a: MetaData <- src if(! (tgt.elements exists (_.key == a.key)))) yield 
//        remove(path.attribute(a.qname(owner)), attr(a.copy(Null)))).toList
//}
//
////private def diff(src: NodeSeq, tgt: NodeSeq, path: LocationPath, cs: List[Command]): List[Command] = (src,tgt) match {
////  case (Empty, Empty) =>
////    cs
////  case (Empty, Seq(ht@Text(_), tt@_*)) =>
////    //diff(Empty, tgt.drop(1), path, append(path--, elem(ht)) :: cs)
////    diff(Empty, tt, path, append(path--, elem(ht)) :: cs)
////  case (Empty, Seq(ht, tt@_*)) =>
////    diff(Empty, tt, path, append(path.parent, elem(ht)) :: cs) // fix #5
////  case (Seq(hs@Text(_), ts@_*), Empty) =>
////    diff(ts, Empty, path++, remove(path.parent.text, elem(hs)) :: cs)
////  case (Seq(hs, ts@_*), Empty) =>
////    diff(ts, Empty, path++, remove(path, elem(hs)) :: cs)
////  case (Seq(hs@Text(l), ts@_*), Seq(ht@Text(r), tt@_*)) if l == r =>
////    cs
////  case (Seq(hs@Text(_), ts@_*), Seq(ht@Text(_), tt@_*)) =>
////    diff(ts, tt, if(ts isEmpty) path-- else path++, update(path.parent.text, elem(ht)) :: cs)
//////@draft
//////    case (Seq(hs@Text(_), ts@_*), Seq(ht@Text(_), tt@_*)) =>
//////      diff(ts, tt, if(ts isEmpty) path-- else path++, patch(path.parent.text, delta(scaup.util.Differ.diff(hs.text, ht.text))) :: cs)
////  case (Seq(hs, ts@_*), _) =>
////    ((slit: Slit[Node]) =>
////      diff(ts, slit.after, if(ts isEmpty) path-- else path++, slit.focus match {
////        case Some(f) =>
////          diff(hs.child, f.child, if(hs.child isEmpty) path else path.childAt(1),
////               diff(hs, hs.attributes, f.attributes, path) ::: (slit.before match {
////                 case Some(es) => List(before(path, (es map elem):_*))
////                 case _        => Nil
////               }) ::: cs)
////        case _ =>
////          (slit.before match {
////            case Some(es) => List(before(path, (es map elem):_*))
////            case _        => Nil
////          }) ::: List(remove(path, elem(hs))) ::: cs
////      })
////    )(findEquivTo(hs, tgt))
////    //@alternative for previous case
////    //@todo test!
//////    case (Seq(hs, ts@_*), _) =>
//////      val insert = (x: Option[Seq[Node]]) => x match {
//////        case Some(es) => before(path, (es map elem):_*) :: Nil
//////        case None     => Nil
//////      }
//////      ((slit: Slit[Node]) =>
//////        diff(ts, slit.after, if(ts isEmpty) path-- else path++, slit.focus match {
//////          case Some(f) => diff(hs.child, f.child, if(hs.child isEmpty) path else path.childAt(1),
//////                               diff(hs, hs.attributes, f.attributes, path) ::: insert(slit.before) ::: cs)            
//////          case _       => insert(slit.before) ::: List(remove(path, elem(hs))) ::: cs
//////        })
//////      )(findEquivTo(hs, tgt))
////  }
////  
////private def diff(owner: Node, src: MetaData, tgt: MetaData, xpath: path.LocationPath) =
////	((for(a: MetaData <- tgt) yield
////       src.elements find (_.key == a.key) match {
////         case Some(k) if (k.value != a.value) => Some(update(xpath.attribute(a.qname(owner)), elem(Text(a.value.text))))
////         case None                            => Some(append(xpath.attributes, attr(a.copy(Null))))
////         case _                               => None
////    }).toList filter (None !=) map (_.get)) ::: 
////     (for(a: MetaData <- src if(! (tgt.elements exists (_.key == a.key)))) yield 
////        remove(xpath.attribute(a.qname(owner)), attr(a.copy(Null)))).toList